// Reference a file-based JavaScript
/// <reference path="../libs/jquery-1.8.0-vsdoc.js" />
/// <reference path="../libs/jquery.jqGrid.src.js" />
/// <reference path="../libs/jshashtable.js" />
/// <reference path="../libs/jquery.numberformatter-1.2.3.min.js" />

/**
* @class GridManager
*/
var gridManager = {
    //CONSTANTS
    //<summary>Constants to be used on all grids</summary>

    /**
    * @cfg
    * @member GridManager
    */
    constants: {
        CLASS_GRIDWRAPPER: 'genGridWrapper',
        CLASS_TYPE_PICTO: 'typePicto',
        CLASS_PREFIX_PICTO: 'picto_',
        CLASS_TEXTWRAPPERNOMARGIN: 'textWrapper textWrapperNoMargin',
        CLASS_TEXTWRAPPER: 'textWrapper',
        CLASS_STATUSPICTO: 'statusPicto',
        CLASS_STATUSPICTO_ERROR: 'statusPicto error'
    },

    /** 
    * Manages the grids of a page to support resize.
    * @property {Object} loadedGrids
    * @private
    */
    loadedGrids: [],

    /**
    * Stores the cell values to be reused later on unformatting.
    * @private
    */
    allGridCellValues: new Hashtable(),

    /**
    * Add a grid to the grid manager.
    * @param {Object} el The grid to add to the GridManager
    */
    addGrid: function (el) {
        this.loadedGrids.push(el);
    },


    /**
    * Removes a grid on the grid manager and destroy it.
    * @param {Object} el The grid to remove
    */
    removeGrid: function (el) {
        var newLoadedGrids = [];
        var idToRemove = el.attr('id');
        jQuery.each(this.loadedGrids, function (index, item) {
            if (item.attr('id') != idToRemove) {
                newLoadedGrids.push(item);
            }
        });
        this.loadedGrids = newLoadedGrids;
        el.jqGrid('GridUnload');
    },

    /**
    * Updates the width of all the grids of the page.
    */
    updateWidth: function () {
        var self = this;

        window.setTimeout(function () {
            // no updateGrid method in jqGrid so...
            for (var i = 0; i < self.loadedGrids.length; i++) {
                self.updateGridWidth(self.loadedGrids[i]);
            }
        }, 100);
    },

    /**
    * @private
    * Updates the width of a specific grid.
    */
    updateGridWidth: function (el) {
        var tw = $(el).parents('.' + this.constants.CLASS_GRIDWRAPPER).width(); // target width
        if (typeof (tw) == 'number')
            $(el).setGridWidth(tw, true);
    },

    /**
    * Initialize the grid for storing cell values.
    * @param {Object} internalGrid The grid to initialize.
    */
    initializeGridValues: function (internalGrid) {
        if (this.allGridCellValues.containsKey(internalGrid)) {
            this.allGridCellValues.remove(internalGrid);
        }
        this.allGridCellValues.put(internalGrid, new Hashtable());
    },

    /**
    * Put a value in the container for a grid.
    * @param {Object} internalGrid The grid to initialize.
    * @param {String} key The key of the formatter.
    * @param {String/Number} cellvalue The value to store.
    * @param {Object} options The options of the formatter, for example rowId or colModel.
    */
    putCellValue: function (internalGrid, key, cellvalue, options) {
        ///<summary>Put a value in the container for a grid</summary>
        /// <param name="internalGrid" type="Grid">the grid to initialize.</param>
        /// <param name="key" type="string">key of the formatter</param>
        /// <param name="cellvalue" type="object">value to store</param>
        /// <param name="options" type="object">options of the formatter {rowId, colModel}</param>
        if (this.allGridCellValues.containsKey(internalGrid)) {
            var cellValues = new Hashtable();
            var gridValues = this.allGridCellValues.get(internalGrid);
            if (!gridValues.containsKey(key)) {
                options.colModel.oldCellValue = cellValues;
                gridValues.put(key, cellValues);
            } else {
                cellValues = gridValues.get(key);
            }
            cellValues.put(options.rowId, cellvalue);
        }
    },

    getCellValue: function (cellvalue, options) {
        ///<summary>Retrieve a cell value from the stored ones</summary>
        /// <param name="cellvalue" type="string">current value for the cell (formatted)</param>
        /// <param name="options" type="object">options of the formatter {rowId, colModel}</param>
        if (typeof (options.colModel.oldCellValue) != 'undefined') {
            return options.colModel.oldCellValue.get(options.rowId);
        } else {
            return cellvalue;
        }
    }
};

/**
* Format the roles based on the information received. CellValue is a string with the list of the roles
* @member GridManager.Formatter
* @uses jQuery
* @uses jqGrid
* @return html
*/
jQuery.extend($.fn.fmatter, {
    multiRoleFormatter: function (cellvalue, options, rowdata) {
        var tab = cellvalue.split(', ');
        var parent = $('<div/>');
        gridManager.putCellValue(this, "multiRoleFormatter", cellvalue, options);
        for (var i = 0; i < tab.length; i++) {
            var roleText = tab[i].toUpperCase();
            if (roleText != "NONE") {
                $('<span/>', {
                    'class': gridManager.constants.CLASS_TYPE_PICTO
                }).html(roleText).appendTo(parent);                
            }
        }
        return parent.html();
    }
});
jQuery.extend($.fn.fmatter.multiRoleFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the roles.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});

jQuery.extend($.fn.fmatter, {
    roleFormatter: function (cellvalue, options, rowdata) {
        var parent = $('<div/>');
        gridManager.putCellValue(this, "roleFormatter", cellvalue, options);
        $('<span/>', {
            'class': gridManager.constants.CLASS_TYPE_PICTO
        }).html(cellvalue.toUpperCase()).appendTo(parent);
        return parent.html();
    }
});
jQuery.extend($.fn.fmatter.roleFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the validity column.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});

jQuery.extend($.fn.fmatter, {
    validityFormatter: function (cellvalue, options, rowdata) {
        //<summary>Display a validity picto on the column. It assumes that a bool value is sent with name "validity"</summary>
        gridManager.putCellValue(this, "validityFormatter", cellvalue, options);
        if (typeof (rowdata.validity) != 'undefined') {
            //We assume that the full row has the proper style applied so we do not care
            var parent = $('<div/>');
            var wrap = $('<div/>', {
                'class': gridManager.constants.CLASS_TEXTWRAPPER,
                'text': cellvalue
            }).appendTo(parent);
            if (rowdata.validity) {
                $('<span/>', {
                    'class': gridManager.constants.CLASS_STATUSPICTO
                }).appendTo(parent);
            } else {
                $('<span/>', {
                    'class': gridManager.constants.CLASS_STATUSPICTO_ERROR
                }).appendTo(parent);
            }
            return parent.html();
        } else {
            return cellvalue;
        }
    },
    thumnailImageFormatter: function (cellvalue, options, rowdata) {
        gridManager.putCellValue(this, "thumnailImageFormatter", cellvalue, options);
        if (typeof (rowdata.thumnailImageFormatter) != 'undefined') {
            //We assume that the full row has the proper style applied so we do not care
            var parent = $('<div/>');
            var wrap = $('<img/>', {
                'src': cellvalue,
                'width': '32px',
                'height': '32px'
            }).appendTo(parent);
            
            return parent.html();
        } else {
            return cellvalue;
        }
    }
});
jQuery.extend($.fn.fmatter.validityFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the validity column.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});

jQuery.extend($.fn.fmatter, {
    templateFormatter: function (cellvalue, options, rowdata) {
        //<summary>Call a template to render the content of the cell, please note that one element of the template must use the cellvalue and have a class of type innerCellValue to retrieve the data back</summary>
        gridManager.putCellValue(this, "templateFormatter", cellvalue, options);
        if (typeof (options.colModel.formatOptions.template) != 'undefined') {
            var model = {
                id: options.rowId,
                data: cellvalue 
            };
            return $(options.colModel.formatOptions.template(model)).data('innerCellValue', cellvalue);
        } else {
            return cellvalue;
        }
    }
});
jQuery.extend($.fn.fmatter.templateFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the templated column finding the element with class innerCellValue.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});


jQuery.extend($.fn.fmatter, {
    currencyFormatter: function (cellvalue, options, rowdata) {
        //<summary>Format a currency cell we suppose that it is an object with the following structure {currency:string , value: number }</summary>
        gridManager.putCellValue(this, "currencyFormatter", cellvalue, options);
        if ((typeof (cellvalue.currency) != 'undefined') && (typeof (cellvalue.value) != 'undefined')) {
            var parent = $('<div/>');
            var wrap = $('<span/>', {
                'text': cellvalue.value
            }).data('innerCellValue', cellvalue).appendTo(parent);

            $('<span/>', {
                'class': 'currency'
            }).appendTo(parent);
            return parent.html();
        } else {
            return cellvalue;
        }
    }
});
jQuery.extend($.fn.fmatter.currencyFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the currency.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});

jQuery.extend($.fn.fmatter, {
    percentageFormatter: function (cellvalue, options, rowdata) {
        //<summary>Format a currency cell we suppose that it is an object with the following structure {currency:string , value: number }</summary>
        gridManager.putCellValue(this, "percentageFormatter", cellvalue, options);
        var parent = $('<div/>');
        var wrap = $('<span/>', {
            'text': cellvalue
        }).appendTo(parent);
        wrap.formatNumber({ format: ',##0.00', locale: 'us' });
        var percent = $('<span/>', {
            'text': '%'
        }).appendTo(parent);
        return parent.html();
    }
});
jQuery.extend($.fn.fmatter.percentageFormatter, {
    unformat: function (cellvalue, options, cellObject) {
        //<summary>Unformat the currency.</summary>
        return gridManager.getCellValue(cellvalue, options);
    }
});



//Inline Editors

/*
For currency
        // Select : jquery ui
        $('#' + rowID).find('select').selectmenu({
            style: 'dropdown'
        });

        // help grid to save select data (from other cell)
        if ($('#' + rowID).find('.currencyCell')) {
            $('#' + rowID).find('.currencyCell').append($('#' + rowID).find('.currencyCell').prev().find('select'));
        }


                // delete duplicate currency
        if (row.find('.currencyCell').length > 0) {
            var cc = $('#' + rowID).find('.currencyCell');
            cc.prev().append('<span class="currency"> ' + cc.html() + '</span>');
        }
        // bank account
        if (row.find('.bankAccount').length > -1) {
            // account initialization
            var filename = row.find('.bankAccount').text();
            if (row.find('.bankAccount a').length > 0) filename = row.find('.bankAccount a').text();
            row.find('.bankAccount').empty().html(filename);
        }


        // document loader addon
            if (row.find('.bankAccount') && $('#popinBank_add dd:eq(1) input[type=text]').length > 0) {
                row.find('.bankAccount').empty().append($('#popinBank_add dd:eq(0) a').text()); // filename
                row.find('.bankAccount').next().empty().append($('#popinBank_add dd:eq(0) a').attr('href')); // file url
                row.find('.bankAccount').next().next().empty().append($('#popinBank_add dd:eq(1) input[type=text]')); // bank name
                row.find('.bankAccount').next().next().next().empty().append($('#popinBank_add dd:eq(1) input[type=checkbox]')); // legalized
                row.find('.bankAccount').next().next().next().next().empty().append($('#popinBank_add dd:eq(2) input[type=text]')); // expiry date
                row.find('.bankAccount').next().next().next().next().next().empty().append($('#popinBank_add dd:eq(3) textarea')); // comments
            }

            // ACTION: bank account
            var buttonWrapper = $('<div/>', { 'class': 'buttonWrapper' });
            var buttonLink = $('<a/>', { 'class': 'button2', html: '<span class="wrap">' + l10n.grid.actions.Add + '</span>' });
            buttonWrapper.append(buttonLink);
            row.find('.bankAccount').empty().html(buttonWrapper);
            row.find('.bankAccount .buttonWrapper').append(row.find('.bankAccount').next().find('input[type=file]')); // re allocate file input

            buttonLink.unbind('click'); // prevent action click

            row.find('.bankAccount input').change(function (e) {
                // apply effect (prevent change before load)
                $(this).unbind('change').hide(); // can afford cancel function
                $(this).parent().addClass('buttonWrapperLoad');
                $(this).prev().empty().prepend('<span class="loader"><!-- --></span><span class="wrap loaderWrap">' + l10n.loading + '</span>');

                // launch ajax function to load
                $.ajax({
                    url: ct.jqGrid('getGridParam', 'saveFileUrl'),
                    data: $(this).val(),
                    dataType: "html",
                    success: function (data) {
                        // success
                        row.find('.bankAccount').empty().append(data);
                        grid.popinAddFile(rowID);
                    }
                });
            });


            popinAddFile: function (rowID) {
        // Popin creation
        $('#popinBank_add').remove(); // delete duplicate

        var row = $('#' + rowID);
        var ct = row.parents('table');
        var cc = row.find('.bankAccount');
        var popin = $('<div/>', { 'class': 'bankPopin', 'id': 'popinBank_add' });
        var top = '<div class="top"><div class="topLeft"><!--  --></div><span class="arrow"><!--  --></span></div>';
        var inner = $('<div/>', { 'class': 'bankPopinInner' });
        var listBank = $('<dl/>');
        listBank.append('<dt>' + l10n.grid.labels.document + ':</dt><dd></dd>');
        listBank.append('<dt><label for="">' + l10n.grid.labels.bankName + ':</label></dt><dd></dd>');
        listBank.append('<dt><label for="">' + l10n.grid.labels.expiryDate + ':</label></dt><dd></dd>');
        listBank.append('<dt><label for="">' + l10n.grid.labels.comments + ':</label></dt><dd></dd>');

        listBank.find('dd:eq(0)').append(cc.find('a')); // re allocate link when ajax performed
        cc.html(l10n.grid.messages.done); // print message when ajax performed

        listBank.find('dd:eq(1)').append(cc.next().next().find('input')); listBank.find('dt:eq(1) label').attr('for', listBank.find('dd:eq(1) input').attr('id'));
        listBank.find('dd:eq(1)').append(cc.next().next().next().find('input'));
        listBank.find('dd:eq(1)').append($('<label/>', { 'text': l10n.grid.labels.legalized, 'for': listBank.find('dd:eq(1) input[type=checkbox]').attr('id') }));
        listBank.find('dd:eq(2)').append(cc.next().next().next().next().find('input')); listBank.find('dt:eq(2) label').attr('for', listBank.find('dd:eq(2) input').attr('id'));
        listBank.find('dd:eq(2) input[type=text]').addClass('datepicker');
        listBank.find('dd:eq(3)').append(cc.next().next().next().next().next().find('textarea')); listBank.find('dt:eq(3) label').attr('for', listBank.find('dd:eq(3) textarea').attr('id'));

        inner.append(listBank);
        var bottom = '<div class="bottom"><div class="bottomLeft"><!--  --></div></div>';
        popin.append(top).append(inner).append(bottom);
        ct.parents('.genGridWrapper').append(popin);
        popin.css({ 'top': cc.offset().top - ct.offset().top + 135, 'left': cc.offset().left - ct.offset().left });

        datepicker.init({
            wrapper: popin,
            icon: true,
            fromTo: false
        });
        popin.fadeIn('fast');

    },


*/

var grid = {
    params: {
        c_error: 'error',
        c_valid: 'valid',
        c_select: 'selectedState',

        //Zebra strippes
        altclass: 'odd',
        altRows: true,

        c_collapseExpandable: 'collapseExpandable',
        c_multiselectable: 'multiselectable',
        c_validateCell: 'validationActions',
        c_validate: 'validButton',
        c_invalidate: 'invalidButton',
        c_mainLoader: 'h3 .loader',
        c_multiConfirmLoader: '.multiConfirm .loader',
        c_showLoader: 'show',
        c_multiConfirm: 'multiConfirm',
        c_showMultiConfirm: 'show',
        c_multiConfirmAccept: 'acceptButton',

        c_modifyCell: 'modifyActions',
        c_modify: 'modifyButton',
        c_erase: 'eraseButton',
        c_cancel: 'cancelButton',
        c_add: 'addButton',
        c_save: 'saveButton',

        c_editable: 'pictoEditable',
        c_editableAble: 'able',
        c_editableUnable: 'unable',
        c_firstLoad: true,
        afterInsertRow: function (rowid, aData, rowelem) {
            // even / odd css classes
            // valid / invalid classes
            // add/modify/remove classes
            var el = $(this);
            grid.afterInsertRowCallback(el, rowid, aData, rowelem);
            // test if roleCustom
            if (this.p.roleCustom) {
                // replace column
                grid.editableRow(this, rowid);
            }
        },

        beforeProcessing: function (data, status, xhr) {
            ///<summary>Initialize the grid just after the data has been loaded and the processing can be performed.</summary>
            gridManager.initializeGridValues(this);
        },
        beforeRequest: function () {
            // Init default Search
            var defaultSearchOptions = [];
            var colModel = this.p.colModel;
            // loop trough each column and check if they have an default value in search options
            // and add them to the array
            $.each(colModel, function (index, column) {
                if (column.hasOwnProperty('searchoptions')) {
                    var searchOptions = column.searchoptions;
                    if (searchOptions.hasOwnProperty('defaultValue')) {
                        defaultSearchOptions[defaultSearchOptions.length++] =
                        {
                            "field": column.index,
                            "op": "bw",
                            "data": searchOptions.defaultValue
                        };
                    }
                }
            });

            // if there are any default search options retrieve the post data
            if (defaultSearchOptions.length > 0) {
                var postData = this.p.postData;
                var filters = {};
                // check if post data already has filters
                if (postData.hasOwnProperty('filters')) {
                    filters = JSON.parse(postData.filters);
                }
                var rules = [];
                // check if filtes already has rules
                if (filters.hasOwnProperty('rules')) {
                    rules = filters.rules;
                }
                // loop trough each default search option and add the search option if the filter rule doesnt exists
                $.each(defaultSearchOptions, function (defaultSearchOptionindex, defaultSearchOption) {
                    var ruleExists = false;
                    $.each(rules, function (index, rule) {
                        if (defaultSearchOption.field == rule.field) {
                            ruleExists = true;
                            return;
                        }
                    });

                    if (ruleExists == false && grid.params.c_firstLoad) {
                        rules.push(defaultSearchOption);
                    }
                });
                filters.groupOp = 'AND';
                filters.rules = rules;
                // set search = true
                postData._search = true;
                grid.params.c_firstLoad = false;
                postData.filters = JSON.stringify(filters);
            }
        },
        gridComplete: function () {

            // update grid width
            gridManager.updateWidth(); // Fix for adapt.js

            // if fullLineClickToggleSubgrid
            if (this.p.fullLineClickToggleSubgrid)
                grid.toggleSubgrid(this);

            if (this.p.fullLineClickRedirectId)
                grid.idRedirect(this);

            if (this.p.confirmGrid)
                grid.confirmGrid(this);


            if (this.p.editableGrid)
                grid.editableGrid(this);

            // Set the number of records next to the grid caption
            // TODO: use culture set by user in UserPreferences
            var getRecords = $(this).getGridParam('records');
            var gridId = $(this).attr('id');
            if (typeof (getRecords) == 'number' && getRecords > 0) {
                $(this).parents('.' + gridManager.constants.CLASS_GRIDWRAPPER).find('h3').find('.wrapNotify_' + gridId).html(getRecords).formatNumber({ format: '#,###', locale: 'us' });
            } else {
                $(this).parents('.' + gridManager.constants.CLASS_GRIDWRAPPER).find('h3').find('.wrapNotify_' + gridId).html(getRecords);
            }
        }
    },
    init: function (el, params) {

        params = $.extend(params, grid.params);
        grid.params.c_firstLoad = true;
        // Initialize the handler once in memory
        $(el).ajaxHandler({ autoLoad: false });

        // add container css class
        var parent = $(el).parent();

        // generic class
        parent.addClass(gridManager.constants.CLASS_GRIDWRAPPER);

        // collapsable / expandable grid
        if (params.subGrid)
            parent.addClass(params.c_collapseExpandable);

        // multiselect grid
        if (params.multiselect)
            parent.addClass(params.c_multiselectable);

        // jqgrid call
        var curGrid = $(el).jqGrid(params);

        // cache loaded grid
        gridManager.addGrid(curGrid);

        // update width
        gridManager.updateGridWidth(curGrid);

        var gridID = curGrid.attr('id');
        $('#printcmd' + gridID).data('plugin_ajaxHandler', null);
        $('#printcmd' + gridID).ajaxHandler({
            cache: false,
            autoLoad: false,
            useWaiting: true,
            async: true,
            onSuccess: function (data) {
                $(data).printElement({ printMode: 'popup' });
            }
        });
    },

    editableRow: function (e, rowid) {
        var el = $(e);
        var cellValue = el.getCell(rowid, e.p.editableRowColumn);

        var modify;
        if (cellValue == 'edit') {
            // editable
            modify = $('<a/>', {
                'href': '#',
                'class': e.p.c_editable + ' ' + e.p.c_editableAble
            });
        } else {
            // not editable
            modify = $('<span/>', {
                'class': e.p.c_editable + ' ' + e.p.c_editableUnable
            });
        }

        // set cell html
        var rowActions = $('<div/>').append(modify).html();
        el.setCell(rowid, e.p.editableRowColumn, rowActions);

        // bind click
        if (cellValue == 'edit') {
            var actionsCell = el.find('[id="' + rowid + '"] td:last');

            // catch default click
            actionsCell.unbind('click').click(function (e) {
                // unbind click on action cell
                e.preventDefault();
                e.stopPropagation();
            });

            // bind
            actionsCell.find('.' + e.p.c_editableAble).click(function (e) {
                e.preventDefault();
                e.stopPropagation();
                // Edit line
                var id = $(this).parents('tr').attr('id');
                el.editRow(id, false, grid.prepareEdit, false, false, false, false, false, grid.prepareRestore);
            });
        }
    },

    // -- clics on grid defined here -----
    toggleSubgrid: function (el) {
        var ct = $(el);

        // catch click & open subgrid
        $(el).find('.jqgrow').unbind('click').click(function (e) {
            e.preventDefault();
            e.stopPropagation();

            grid.rowClick(ct, $(this), this.id);
        });
    },

    idRedirect: function (el) {
        var ct = $(el);

        // catch click, get id & redirect
        $(el).find('.jqgrow').unbind('click').click(function (e) {
            e.preventDefault();
            e.stopPropagation();

            var url = ct[0].p.redirectUrl;
            var paramValue = ct.jqGrid('getRowData', this.id).paramValue;
            var paramName = ct[0].p.redirectParamName;

            w.location = url.indexOf('?') > -1 ? url + '&' + paramName + '=' + paramValue : url + '?' + paramName + '=' + paramValue;
        });
    },

    editableGrid: function (el) {
        var ct = $(el);
        var container = ct.parents('.' + gridManager.constants.CLASS_GRIDWRAPPER);
        var actionsWrapper = container.find('.' + el.p.c_multiConfirm);
        var ids = ct.jqGrid('getDataIDs');

        // set html
        for (var i = 0; i < ids.length; i++) {
            grid.createActionsButton(ids[i])
        }

        if (ids.length == 0) {

            // Show AddForm
            parameters = {
                rowID: "form_row",
                initData: {},
                position: "last",
                useDefValues: false,
                useFormatter: false,
                addRowParams: { extraparam: {} }
            }
            ct.jqGrid('addRow', parameters);
            grid.prepareEdit('form_row');
            $('#form_row').removeClass('ui-state-highlight'); // prevent highlight color
        }

    },

    prepareEdit: function (rowID) {
        // callback after editline
        // edit actions buttons
        grid.createActionsButton(rowID);

        // Date : jquery ui
        datepicker.init({
            wrapper: $('#' + rowID),
            icon: true,
            fromTo: true
        });
    },

    prepareRestore: function (rowID) {
        // callback before restore row
        var row = $('#' + rowID);

        // reedit actions buttons
        var actionsCell = row.find('td:last');
        actionsCell.find('.' + grid.params.c_cancel).remove();
        grid.createActionsButton(rowID);
    },

    createActionsButton: function (rowID) {
        var row = $('#' + rowID);
        var ct = row.parents('table');
        var ids = ct.getDataIDs();
        var paramValue = ct.getRowData(rowID).paramValue;

        if (rowID != 'form_row' && row.attr('editable') != 1) {
            // currently not editing row

            var modify = $('<a/>', {
                'href': '#',
                'class': grid.params.c_modify,
                'text': l10n.grid.actions.modify,
                'title': l10n.grid.actions.modify
            });

            var erase = $('<a/>', {
                'href': '#',
                'class': grid.params.c_erase,
                'text': l10n.grid.actions.erase,
                'title': l10n.grid.actions.erase
            });

            var rowActions = $('<div/>').append(modify).append(erase);

            ct.jqGrid('setRowData', rowID, {
                actions: rowActions.html()
            });

            var actionsCell = ct.find('[id="' + rowID + '"] td:last');
            actionsCell.addClass(grid.params.c_modifyCell);

            // catch click
            actionsCell.unbind('click').click(function (e) {
                // unbind click on action cell
                e.preventDefault();
                e.stopPropagation();
            });

            // ACTION: modify entry
            actionsCell.find('.' + grid.params.c_modify).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                // Edit line
                var id = $(this).parents('tr').attr('id');
                ct.jqGrid('editRow', id, false, grid.prepareEdit, false, false, false, false, false, grid.prepareRestore);

            });
            // ACTION: delete entry
            actionsCell.find('.' + grid.params.c_erase).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                // Erase line
                var id = $(this).parents('tr').attr('id');

                // Ask for confirmation
                if ($('#dialog-confirm')) {
                    $('body').append($('<div/>', { 'id': 'dialog-confirm' }));
                }
                $('#dialog-confirm').attr('title', l10n.grid.messages.confirmEraseTitle).empty().html('<p>' + l10n.grid.messages.confirmEraseDesc + '</p>');

                $("#dialog-confirm").dialog({
                    resizable: false,
                    height: 140,
                    modal: true,
                    buttons: {
                        Confirm: function () {
                            ct.jqGrid('delRowData', id);
                            $(this).dialog("close");
                        },
                        Cancel: function () {
                            $(this).dialog("close");
                        }
                    }
                });

            });
            // Button add
            if (ct.find('[id="' + rowID + '"]').index('tr') == ids.length + 1) {
                if (rowID != 'form_row') {
                    var addCell = ct.find('[id="' + rowID + '"] td:last');
                    var add = $('<a/>', {
                        'href': '#',
                        'class': grid.params.c_add,
                        'text': l10n.grid.actions.add,
                        'title': l10n.grid.actions.add
                    });
                    addCell.append(add);
                    add.bind('click', function () {
                        // Show AddForm
                        parameters = {
                            rowID: "form_row",
                            initData: {},
                            position: "last",
                            useDefValues: false,
                            useFormatter: false,
                            addRowParams: { extraparam: {} }
                        }
                        ct.jqGrid('addRow', parameters);
                        grid.prepareEdit('form_row');
                        $('#form_row').removeClass('ui-state-highlight'); // prevent highlight color
                    })
                }
            }
        } else if (rowID != 'form_row') {
            // currently editing row
            var actionsCell = $('#' + rowID).find('td:last');
            actionsCell.find('.' + grid.params.c_modify + ', .' + grid.params.c_erase + ', .' + grid.params.c_add + ', .' + grid.params.c_cancel + ', .' + grid.params.c_save).remove();
            var cancel = $('<a/>', {
                'href': '#',
                'class': grid.params.c_cancel,
                'text': l10n.grid.actions.cancel,
                'title': l10n.grid.actions.cancel
            });
            var save = $('<a/>', {
                'href': '#',
                'class': grid.params.c_save,
                'text': l10n.grid.actions.save,
                'title': l10n.grid.actions.save
            });

            actionsCell.append(cancel).append(save);

            // ACTION: cancel edit
            actionsCell.find('.' + grid.params.c_cancel).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                ct.jqGrid('restoreRow', rowID, grid.prepareRestore);

            });
            // ACTION: save edit
            actionsCell.find('.' + grid.params.c_save).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                saveparameters = {
                    "successfunc": null,
                    "url": ct.jqGrid('getGridParam', 'updateUrl'),
                    "extraparam": {},
                    "aftersavefunc": grid.prepareRestore,
                    "errorfunc": null,
                    "afterrestorefunc": null,
                    "restoreAfterError": true,
                    "mtype": "GET"
                }

                ct.jqGrid('saveRow', rowID, saveparameters);
            });

        } else {
            // currently adding row
            var actionsCell = $('#' + rowID).find('td:last');
            actionsCell.find('.' + grid.params.c_modify + ', .' + grid.params.c_erase + ', .' + grid.params.c_add + ', .' + grid.params.c_cancel + ', .' + grid.params.c_save).remove();
            var cancel = $('<a/>', {
                'href': '#',
                'class': grid.params.c_cancel,
                'text': l10n.grid.actions.cancel,
                'title': l10n.grid.actions.cancel
            });
            var save = $('<a/>', {
                'href': '#',
                'class': grid.params.c_save,
                'text': l10n.grid.actions.save,
                'title': l10n.grid.actions.save
            });

            actionsCell.append(cancel).append(save);

            // ACTION: cancel add form
            actionsCell.find('.' + grid.params.c_cancel).click(function (e) {
                e.preventDefault();
                e.stopPropagation();
                ct.jqGrid('delRowData', rowID);

            });

            // ACTION: save and add row
            actionsCell.find('.' + grid.params.c_save).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                saveparameters = {
                    "successfunc": null,
                    "url": ct.jqGrid('getGridParam', 'saveUrl'),
                    "extraparam": {},
                    "aftersavefunc": grid.saveNewRow,
                    "errorfunc": null,
                    "afterrestorefunc": null,
                    "restoreAfterError": true,
                    "mtype": "GET"
                }
                ct.jqGrid('saveRow', rowID, saveparameters);

            });
        }
    },

    saveNewRow: function (rowID, data) {
        //id must have been provided in the response
        var newID = data.id;
        $('#' + rowID).attr('id', newID).removeClass('jqgrid-new-row ui-state-highlight');
        grid.prepareRestore(newID);
    },

    confirmGrid: function (el) {
        var ct = $(el);
        var container = ct.parents('.' + gridManager.constants.CLASS_GRIDWRAPPER);
        var actionsWrapper = container.find('.' + el.p.c_multiConfirm);
        var ids = ct.jqGrid('getDataIDs');

        var confirmUrl = el.p.confirmUrl;
        var confirmParamName = el.p.confirmParamName;
        var confirmIdsParamName = el.p.confirmIdsParamName;

        confirmUrl = confirmUrl.indexOf('?') > -1 ? confirmUrl + '&' : confirmUrl + '?';

        // catch rowclic
        container.find('input').change(function (e) {
            grid.confirmGridRowClic(el);
        });
        ct.find('.jqgrow').click(function (e) {
            var timer = w.setTimeout(function () {
                grid.confirmGridRowClic(el);
                window.clearTimeout(timer);
            }, 1);
        });

        container.click(function (e) {
            var timer = w.setTimeout(function () {
                grid.confirmGridRowClic(el);
                window.clearTimeout(timer);
            }, 1);
        });

        // catch click on accept reject global buttons
        actionsWrapper.find('a').click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            var accept = $(this).hasClass(el.p.c_multiConfirmAccept) ? 1 : 0;
            var rows = ct.jqGrid('getGridParam', 'selarrrow');
            var ids = grid.getIds(el, rows);
            var url = confirmUrl + confirmParamName + '=' + accept + '&' + confirmIdsParamName + '=' + ids;
            grid.ajaxLoad(el, url, 'multiConfirmLoader');
        });

        // set html
        for (var i = 0; i < ids.length; i++) {
            var cl = ids[i];
            var paramValue = ct.jqGrid('getRowData', cl).paramValue;

            var validate = $('<a/>', {
                'href': confirmUrl + confirmParamName + '=1&' + confirmIdsParamName + '=' + paramValue,
                'class': el.p.c_validate,
                'text': l10n.grid.actions.validate,
                'title': l10n.grid.actions.validate
            });

            var invalidate = $('<a/>', {
                'href': confirmUrl + confirmParamName + '=0&' + confirmIdsParamName + '=' + paramValue,
                'class': el.p.c_invalidate,
                'text': l10n.grid.actions.invalidate,
                'title': l10n.grid.actions.invalidate
            });

            var rowActions = $('<div/>').append(validate).append(invalidate);

            ct.jqGrid('setRowData', cl, {
                actions: rowActions.html()
            });

            var actionsCell = ct.find('[id="' + cl + '"] td:last');
            actionsCell.addClass(el.p.c_validateCell);

            // catch click
            actionsCell.unbind('click').click(function (e) {
                // unbind click on action cell
                e.preventDefault();
                e.stopPropagation();
            });
            actionsCell.find('.' + el.p.c_validate + ', .' + el.p.c_invalidate).click(function (e) {
                e.preventDefault();
                e.stopPropagation();

                var url = $(this).attr('href');
                // ajax call
                grid.ajaxLoad(el, url, 'mainLoader');
            });
        }
    },

    confirmGridRowClic: function (el) {
        var ct = $(el);
        var container = ct.parents('.' + gridManager.constants.CLASS_GRIDWRAPPER);
        var actionsWrapper = container.find('.' + el.p.c_multiConfirm);

        var selected = ct.jqGrid('getGridParam', 'selarrrow');
        selected.length ? actionsWrapper.addClass(el.p.c_showMultiConfirm) : actionsWrapper.removeClass(el.p.c_showMultiConfirm);
    },

    getIds: function (el, ids) {
        var ct = $(el);
        var ret = '';
        for (var i = 0; i < ids.length; i++) {
            var value = ct.jqGrid('getRowData', ids[i]).paramValue;
            ret = i == 0 ? ret + value : ret + ',' + value;
        }
        return ret;
    },

    ajaxLoad: function (el, url, loader) {
        var ct = $(el);
        var container = ct.parents('.' + gridManager.constants.CLASS_GRIDWRAPPER);

        //        grid.loader('show', el, loader);
        //        // ajax call
        //        $.ajax({
        //            url: url,
        //            data: "",
        //            dataType: "html",
        //            async: true,
        //            success: function (data) {
        //                // success
        //                container.html(data);
        //            },
        //            // error
        //            error: ajax.error,
        //            complete: function () {
        //                grid.loader('hide', el, loader);
        //            }
        //        });

        ct.ajaxHandler({
            urlAction: url,
            async: true,
            viewSuccess: container,
            beforeSend: function () {
                grid.loader('show', el, loader);
            },
            onComplete: function () {
                grid.loader('hide', el, loader);
            }
        });
    },

    loader: function (status, el, loader) {
        var ct = $(el);
        var container = ct.parents('.' + gridManager.constants.CLASS_GRIDWRAPPER);

        switch (loader) {
            case 'multiConfirmLoader':
                var item = container.find(el.p.c_multiConfirmLoader);
                break;
            default:
                var item = container.find(el.p.c_mainLoader);
        }
        status == 'show' ? item.addClass(el.p.c_showLoader) : item.removeClass(el.p.c_showLoader);
    },

    rowClick: function (ct, row, id) {
        if (!row.hasClass(grid.params.c_select)) {
            ct.jqGrid('expandSubGridRow', id);
        } else {
            ct.jqGrid('collapseSubGridRow', id);
        }
    },

    showSub: function (ct, target, row, url) {
        var g = $(ct);
        var r = g.find('[id="' + row + '"]');

        // hide showed subcontent
        var p = g.find('.' + ct.p.c_select);
        p.length ? g.jqGrid('collapseSubGridRow', p.attr('id')) : true;

        // highlight line
        r.addClass(ct.p.c_select);

        // add error class on subgrid
        r.hasClass(ct.p.c_error) ? $('#' + target).addClass(ct.p.c_error) : true;

        // ajax load
        var gridId = $(ct).attr('id');
        console.log($(ct));
        subgrid.load(g, target, url, row, gridId);
    },

    hideSub: function (ct, target, row) {
        var g = $(ct);
        var r = g.find('[id="' + row + '"]');

        // remove highlight line
        r.removeClass(ct.p.c_select);

        // empty content
        subgrid.unload(target, row);

    },

    getData: function (rowid) {
        return $('#' + rowid).data('jqgrid.record_data');
    },

    afterInsertRowCallback: function (el, rowid, aData, elem) {
        var row = el.find('[id="' + rowid + '"]');

        // valid / invalid
        if (typeof (aData.validity) != 'undefined') {
            aData.validity.toLowerCase() === 'false' ? row.addClass(grid.params.c_error) : row.addClass(grid.params.c_valid);
        }

        $(row).data('jqgrid.record_data', elem);

    }
};

var subgrid = {
    load: function (el, id, url, row,gridId) {
        el.ajaxHandler({
            urlAction: url,
            async: true,
            viewSuccess: id,
            viewLoading: 'load_' + gridId
        });
    },
    unload: function (id, row) {
        $('#' + id).empty();
    }
};